<?php
namespace Pinenut\Model\ReferenceContainer;
/**
 * Набор связей. Используется когда нужно связать коллекции способом 
 * многие-к-многим и один-к-многим со стороны "многие"
 * 
 * В нем реализуются методы установки связи, получения обратной связи
 * 
 * 
 * @author Kosh
 *
 */
use Pinenut\Model\ReferenceContainer;

class Set extends ReferenceContainer implements \ArrayAccess, \Iterator {

	public function populate(array $data = array(), $fromStore = false) {

		$this->_reference->setParent($this);
		$this->_reference->setField($this->_field);
		
		foreach ($data as $k=>&$v) {
			if (null !== $v) {
				$field = clone $this->_reference;
				$field->populate($v, $fromStore);
				$v = $field;
			}
		}
		
		$this->_container = $data;

		return $this;
	}
	
	public function toArray($forStore = false) {

		$data = array();
		
		foreach ($this->_container as $value) {
			$data[] = $value->toArray($forStore);
		}
		
		return $data;
	}
	
	
	/**
	 * Трогаем связь, если её не было, создаётся пустышка
	 * 
	 * @param string $id
	 * @param array $params
	 * @return \Pinenut\Model\Reference
	 */
	function touchReference($id, array $params = array(), $forSave = false) {
		// прямая связь
		$reference = clone $this->_reference;
		
		if (count($params)) 
			$reference->populate($params);
			
		$reference->_ref = (string)$id;

		
		$refData = $reference->toArray(true);
		
		// вносим изменения в базу, если они требуются
		$this->modify()
			->whereNot('_ref', $refData['_ref'])
			->addToSet(null, $refData)
			->execute();

		return $reference;
	}
	
	
	
	public function getReference( $id = null) {
		
		if (null === $id) 
			return reset($this->_container);

		foreach ($this->_container as $ref) {
			if ((string)$ref->_ref == (string)$id) { // некрасивый типекаст
				return $ref;
			}
		}

		// не нашли - загружаем сырое и добавляем его в контейнер
		$model = $this->getModel();
		$raw = $model->find()
			->where('_id', $model->_id)
			->where($this->_field.'.$._ref', $model::typeCast($id, static::ID))
			->active(false)
			->fields(array($this->_field.'.$'))
			->one();
		
		if ($raw) {
			if (null !== ($data = static::_getFromMultiArrayByPath($raw, $this->_field))) {
				$reference = clone $this->_reference;
				$reference->populate($data, true);
				$this->_container[] = $reference;
				return $reference;
			}
		}
		
	}
	
	// ArrayAccess
	
    public function offsetSet($offset, $value) {
        if (is_null($offset)) {
            $this->_container[] = $value;
        } else {
            $this->_container[$offset] = $value;
        }
    }
    public function offsetExists($offset) {
        return isset($this->_container[$offset]);
    }
    public function offsetUnset($offset) {
        unset($this->_container[$offset]);
    }
    public function offsetGet($offset) {
        return isset($this->_container[$offset]) ? $this->_container[$offset] : null;
    }
    
    // Iterator
    
	function rewind() {
		return reset($this->_container);
	}
	function current() {
		return current($this->_container);
	}
	function key() {
		return key($this->_container);
	}
	function next() {
		return next($this->_container);
	}
	function valid() {
		return key($this->_container) !== null;
	}
}